#pragma once 

#include <queue> 
#include <vector>
#include <unistd.h>
#include <iostream>
#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"

namespace wyl
{
const int g_thread_num = 5; 
pthread_mutex_t _g_mutex = PTHREAD_MUTEX_INITIALIZER;
    template<class T> 
    class ThreadPool
    {
    private:
        ThreadPool(int num = g_thread_num) :_thread_num(num), _threads(num)
        {
            pthread_mutex_init(&_mtx,nullptr); 
            pthread_cond_init(&_cond,nullptr); 
            _con_queue = new std::queue<T>();
            _prod_queue = new std::queue<T>();
        }
        ThreadPool(ThreadPool<T>& tp){} 
        ThreadPool<T>& operator=(ThreadPool<T> tp) const; 
        ~ThreadPool()
        {
            for(auto& it : _threads)
            {
                it->Join();
                delete it; 
            }
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

        bool IsConEmpty(){return _con_queue->empty();}

        void WaitCond(){pthread_cond_wait(&_cond,&_mtx);}
    public: 
        
        static ThreadPool<T>* GetInstance()
        {
            if(_instance == nullptr)
            {
                LockGuard lock(&_g_mutex); 
                if(_instance == nullptr)
                {
                    _instance = new ThreadPool<T>(g_thread_num);
                    _instance->Init();
                    _instance->Run();
                }
            }
            return _instance;
        }

        static void* routine(void* args)
        {
            ThreadDate* td = (ThreadDate*)args;
            ThreadPool<T>* tp = (ThreadPool<T>*)td->_args;
            while(true)
            {
                T t;
                {
                    usleep(5000);
                    LockGuard lock(&tp->_mtx); 
                    while(tp->IsConEmpty()) tp->WaitCond();
                    t = tp->_con_queue->front();
                    tp->_con_queue->pop();
                }
                t();
            }
        }

        void Init()
        {
            for(int i = 0 ;  i < _thread_num ; i ++)
            {
                _threads[i] = new Thread(i + 1, routine,this); 
            }
        }

        //启动线程池
        void Run()
        {
            for(auto& it : _threads)
            {
                it->Start();
                logMessage(NORMAL,"线程启动成功");
            }
        }

        void Push(const T& in)
        {
            LockGuard lock(&_mtx); 
            _prod_queue->push(in); 
            if(IsConEmpty())
            {
               // if(_prod_queue->size() >= 5)
                {
                    std::swap(_con_queue,_prod_queue);
                    pthread_cond_signal(&_cond);
                }
            }
        }
    private:
        int _thread_num;
        std::vector<Thread*> _threads;
        std::queue<T>* _con_queue;  //消费者队列
        std::queue<T>* _prod_queue;  //生产者队列
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;    
        static ThreadPool<T>* _instance;
    };
    template<class T>
    ThreadPool<T>* ThreadPool<T>::_instance = nullptr;

}